package com.atguigu.gmall.activity.recevier;

import com.atguigu.gmall.activity.model.SeckillGoods;
import com.atguigu.gmall.activity.model.UserRecode;
import com.atguigu.gmall.activity.service.SeckillGoodsService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.rabbit.config.MqConst;
import com.atguigu.gmall.common.util.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.rabbitmq.client.Channel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.BoundListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * @author: atguigu
 * @create: 2023-05-13 11:34
 */
@Slf4j
@Component
public class ActivityReceiver {


    @Autowired
    private SeckillGoodsService seckillGoodsService;

    @Autowired
    private RedisTemplate redisTemplate;


    /**
     * 监听秒杀商品预热消息
     * 1.查询数据库中当日参与秒杀商品列表
     * 2.导入到分布式缓存中
     *
     * @param channel
     * @param message
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK, durable = "true"),
            value = @Queue(value = MqConst.QUEUE_TASK_1, durable = "true"),
            key = MqConst.ROUTING_TASK_1
    ))
    public void processSeckillGoodsImport(Channel channel, Message message) {
        try {
            log.info("[秒杀服务]监听到秒杀商品入库消息");
            //1.查询数据库中当日参与秒杀商品列表
            LambdaQueryWrapper<SeckillGoods> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SeckillGoods::getStatus, "1");
            queryWrapper.gt(SeckillGoods::getStockCount, 0);
            String today = DateUtil.formatDate(new Date());
            queryWrapper.apply("date_format(start_time, '%Y-%m-%d') = '" + today + "'");
            List<SeckillGoods> seckillGoodsList = seckillGoodsService.list(queryWrapper);
            if (!CollectionUtils.isEmpty(seckillGoodsList)) {
                //2.导入到分布式缓存中
                //2.1 将参与秒杀商品批量存入Redis - Hash数据类型
                //2.1.1 创建秒杀商品hash结构Key
                String seckillGoodsKey = RedisConst.SECKILL_GOODS;
                //2.1.2 创建hash操作对象
                BoundHashOperations<String, String, SeckillGoods> hashOps = redisTemplate.boundHashOps(seckillGoodsKey);
                seckillGoodsList.stream().forEach(seckillGoods -> {
                    if (!hashOps.hasKey(seckillGoods.getSkuId().toString())) {
                        //2.1.3 便利秒杀商品列表存入Redis即可
                        hashOps.put(seckillGoods.getSkuId().toString(), seckillGoods);

                        //2.2 将每件参与秒杀商品库存存入Redis  -- List数据类型
                        //2.2.1 创建商品库存List结构Key
                        String seckillGoodsStockKey = RedisConst.SECKILL_STOCK_PREFIX + seckillGoods.getSkuId();
                        //2.2.2 创建商品库存List操作对象
                        BoundListOperations<String, String> listOps = redisTemplate.boundListOps(seckillGoodsStockKey);

                        //2.2.3 遍历商品库存数量存入List
                        for (Integer i = 0; i < seckillGoods.getStockCount(); i++) {
                            listOps.leftPush(seckillGoods.getSkuId().toString());
                        }

                        //3.将导入秒杀商品状态存入每个秒杀服务实例本地缓存中 发送消息到Redis
                        redisTemplate.convertAndSend("seckillpush", seckillGoods.getSkuId() + ":1");
                    }
                });
            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        }
    }


    /**
     * 监听秒杀队列中购买意向,完成秒杀核心业务-获取抢购资格
     *
     * @param userRecode
     * @param channel
     * @param message
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_USER, durable = "true"),
            value = @Queue(value = MqConst.QUEUE_SECKILL_USER, durable = "true"),
            key = MqConst.ROUTING_SECKILL_USER
    ))
    public void processSeckillRequest(UserRecode userRecode, Channel channel, Message message) {
        try {
            if (userRecode != null) {
                log.info("[秒杀服务]监听到秒杀请求:{}", userRecode);
                seckillGoodsService.processSeckillRequest(userRecode);
            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        }
    }


    /**
     * 监听获取到秒杀资格后,扣减秒杀库存
     *
     * @param skuId   商品ID
     * @param channel
     * @param message
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_SECKILL_STOCK, durable = "true"),
            value = @Queue(value = MqConst.QUEUE_SECKILL_STOCK, durable = "true"),
            key = MqConst.ROUTING_SECKILL_STOCK
    ))
    public void processDeductStock(Long skuId, Channel channel, Message message) {
        try {
            if (skuId != null) {
                log.info("[秒杀服务]监听到秒杀扣库存:{}", skuId);
                seckillGoodsService.deductSecKillStock(skuId);
            }
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        }
    }

    /**
     * 将当日产生秒杀缓存全部清理
     * @param channel
     * @param message
     */
    @SneakyThrows
    @RabbitListener(bindings = @QueueBinding(
            exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_TASK, durable = "true"),
            value = @Queue(value = MqConst.QUEUE_TASK_18, durable = "true"),
            key = MqConst.ROUTING_TASK_18
    ))
    public void processCleanCache(Channel channel, Message message) {
        try {
            log.info("[秒杀服务]监听到清理秒杀缓存消息");
            seckillGoodsService.processCleanCache();
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

        } catch (Exception e) {
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        }
    }
}
